package com.boot2.core.utils.upload;

import com.aliyun.oss.OSS;
import com.boot2.core.conf.TencentProperties;
import com.boot2.core.conf.upload.OssProperties;
import com.boot2.core.constant.CoreConstant;
import com.boot2.core.constant.UploadUrlConstant;
import com.boot2.core.dict.CommonEnum;
import com.boot2.core.exception.BusinessException;
import com.boot2.core.utils.DateUtil;
import com.boot2.core.utils.FileUtil;
import com.boot2.core.utils.ImageUtil;
import com.boot2.core.utils.StringUtils;
import com.boot2.core.web.RequestContext;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import lombok.extern.apachecommons.CommonsLog;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhangweilin
 * @Description: 文件上传基础
 * @date 2020/7/11
 */
@CommonsLog
public class AbstractFileUploadUtil {

    /**
     * 上传的原始图片列表对应的map key，只在文件上传时使用
     */
    private static final String originalListKey = "originalList";

    /**
     * 上传的经过包括后的图片列表对应的map key，如水印图片，缩略图片等，只在文件上传时使用
     */
    private static final String wrappedListKey = "wrappedList";


    /**
     * 多文件上传
     *
     * @param files    多文件
     * @param fileType 此为枚举，只支持图片和普通文件
     * @return
     * @throws IOException
     */
    protected static Map<String, List<String>> uploadFiles(MultipartFile[] files, CommonEnum.FileType fileType, String subDir) {
        List<String> originalList = new ArrayList<>();
        List<String> wrappedList = new ArrayList<>();
        Map<String, List<String>> imagePathListMap = new HashMap<>();

        for (MultipartFile multipartFile : files) {
            Map<String, List<String>> imagePathListMap0 = uploadFile(multipartFile, fileType, subDir, null);
            warpImageList(originalList, wrappedList, imagePathListMap0);
        }
        if (CollectionUtils.isNotEmpty(originalList)) {
            imagePathListMap.put(originalListKey, originalList);
        }
        if (CollectionUtils.isNotEmpty(wrappedList)) {
            imagePathListMap.put(wrappedListKey, wrappedList);
        }
        return imagePathListMap;
    }

    private static void warpImageList(List<String> originalList, List<String> wrappedList, Map<String, List<String>> imagePathListMap0) {
        if (null != imagePathListMap0) {
            List<String> originalList0 = imagePathListMap0.get(originalListKey);
            List<String> wrappedList0 = imagePathListMap0.get(wrappedListKey);
            originalList.addAll(originalList0);
            wrappedList.addAll(wrappedList0);
        }
    }

    /**
     * 多文件上传
     *
     * @param files       多图片
     * @param fileType    此为枚举，只支持图片和普通文件
     * @param imgParamMap 图片处理参数，包括缩略图，和水印等
     * @param subDir      如果上传路径下面再有子目录，直接传过来，子目录的路径，需要外面计算好再传
     * @return
     * @throws IOException
     */
    protected static Map<String, List<String>> uploadFiles(MultipartFile[] files, CommonEnum.FileType fileType, Map<String, Object> imgParamMap, String subDir) {
        List<String> originalList = new ArrayList<>();
        List<String> wrappedList = new ArrayList<>();
        Map<String, List<String>> imagePathListMap = new HashMap<>();

        List<String> realNames = new ArrayList<String>();
        for (MultipartFile multipartFile : files) {
            Map<String, List<String>> imagePathListMap0 = uploadFile(multipartFile, fileType, subDir, imgParamMap);
            warpImageList(originalList, wrappedList, imagePathListMap0);
        }
        if (CollectionUtils.isNotEmpty(originalList)) {
            imagePathListMap.put(originalListKey, originalList);
        }
        if (CollectionUtils.isNotEmpty(wrappedList)) {
            imagePathListMap.put(wrappedListKey, wrappedList);
        }
        return imagePathListMap;
    }

    /**
     * 单文件上传
     *
     * @param file        单个文件
     * @param fileType    文件类型,只支持图片和普通文件
     * @param subDir      如果上传路径下面再有子目录，直接传过来，子目录的路径，需要外面计算好再传
     * @param imgParamMap 图片处理参数，包括缩略图，和水印
     * @return
     * @throws IOException
     */
    protected static Map<String, List<String>> uploadFile(MultipartFile file, CommonEnum.FileType fileType, String subDir, Map<String, Object> imgParamMap) {
        List<String> originalList = new ArrayList<>();
        List<String> wrappedList = new ArrayList<>();
        String fileName = file.getOriginalFilename();
        String suffix = "";
        String realName = "";
        String originalFileUri = "";
        // 如果有后缀
        if (fileName.contains(".")) {
            suffix = FileUtil.getSuffix(fileName);
        } else {
            suffix = fileName;
        }

        if (!file.isEmpty()) {
//            realName = StringUtils.getRandomString(3) + "_" + System.nanoTime() + suffix;
            realName = getRandomFileName(file);
            // 默认情况下为图片 上传

            // 默认为图片
            String dirPrefix = UploadUrlConstant.imgUploadDir;
            String urlPrefix = UploadUrlConstant.imgUrl;

            //图片
            if (CommonEnum.FileType.File.equals(fileType)) {
                dirPrefix = UploadUrlConstant.fileUploadDir;
                urlPrefix = UploadUrlConstant.fileUrl;
            }
            // 子文件夹
            if (StringUtils.isNotEmpty(subDir)) {
                realName = ((subDir == null) ? "" : subDir.toLowerCase() + "/") + realName;
            }
            String fileName0 = dirPrefix + realName;
            originalFileUri = urlPrefix + realName;

            File file2 = null;
            file2 = writeFile(file, fileName0);

            // 在基本的上传完图片后，如果有其它要操作的指令，从map中读取，比如缩放，比如加水印等
            String wrapImageUrl = wrapImage(imgParamMap, file2);
            if (wrapImageUrl != null) {
                wrapImageUrl = ((subDir == null) ? "" : subDir.toLowerCase() + "/") + wrapImageUrl;
            }
            boolean isWrapImageName = false;
            if (StringUtils.isNotEmptyString(wrapImageUrl)) {
                isWrapImageName = true;
            }
            fileName0 = dirPrefix + wrapImageUrl;
            wrapImageUrl = urlPrefix + wrapImageUrl;
//            file2 = writeFile(file, fileName0);

            if (isWrapImageName) {
                wrappedList.add(wrapImageUrl);
            }
            originalList.add(originalFileUri);

            Map<String, List<String>> imagePathListMap = new HashMap<>();
            imagePathListMap.put(wrappedListKey, wrappedList);
            imagePathListMap.put(originalListKey, originalList);
            return imagePathListMap;
        }
        return null;
    }

    /**
     * 上传文件到阿里oss
     *
     * @param file
     * @param ossProperties
     * @param ossClient
     * @param subDir
     * @return
     */
    protected static String uploadFile2Oss(MultipartFile file, OssProperties ossProperties, OSS ossClient, String subDir) {
        subDir = StringUtils.isEmpty(subDir) ? "upload/" : subDir;
        Assert.notNull(file, "the file can not be null");
        Assert.isTrue(!file.isEmpty(), "the file can not be empty");
        // 上传
        long time = System.currentTimeMillis();
        String realName = getRandomFileName(file);
        try {
            ossClient.putObject(ossProperties.getBucketName(), subDir + realName, new ByteArrayInputStream(file.getBytes()));
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException("the file is invalid ", e);
        }
        //反正这个过期时间，我是活不到
        Date expiration = new Date(time + 3600L * 1000 * 24 * 365 * 200);
        String url = ossClient.generatePresignedUrl(ossProperties.getBucketName(), realName, expiration).toString();
        if (url.contains("?")) {
            url = url.substring(0, url.indexOf("?"));
        }
        String uri = StringUtils.getLastSection(url, "/");
        return subDir + uri;
    }

    /**
     * 上传文件到腾讯COS
     *
     * @param file
     * @param tencentProperties
     * @param cosclient
     * @param subDir
     * @return
     */
    protected static String uploadFile2TencentCos(MultipartFile file, TencentProperties tencentProperties, COSClient cosclient, String subDir) {
        subDir = StringUtils.isEmpty(subDir) ? "upload/" : subDir;
        Assert.notNull(file, "the file can not be null");
        Assert.isTrue(!file.isEmpty(), "the file can not be empty");
        // 上传
        String realName = getRandomFileName(file);
        Date date = new Date();
        int year = DateUtil.getYear(date);
        int month = DateUtil.getMonth(date);
        int day = DateUtil.getDay(date);
        // 指定要上传到 COS 上的路径
        String key = subDir + "/" + year + "/" + month + "/" + day + "/" + realName;
        try {
            ObjectMetadata objectMetadata = new ObjectMetadata();
            PutObjectRequest putObjectRequest = new PutObjectRequest(tencentProperties.getBucketName(), key, new ByteArrayInputStream(file.getBytes()), objectMetadata);
            PutObjectResult putObjectResult = cosclient.putObject(putObjectRequest);
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException("the file is invalid ", e);
        }
        return key;
    }

    /**
     * 根据随机获取文件名
     *
     * @param file
     * @return
     */
    protected static String getRandomFileName(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        //如果使用原名
        Boolean uploadOriginalName = (Boolean) RequestContext.getRequest().getAttribute(CoreConstant.uploadOriginalName);
        if (null != uploadOriginalName && uploadOriginalName) {
            return fileName;
        }
        String suffix = "";
        String realName = "";
        // 如果有后缀
        if (fileName.contains(".")) {
            suffix = FileUtil.getSuffix(fileName);
        } else {
            suffix = fileName;
        }
        realName = StringUtils.getRandomString(3) + "_" + System.nanoTime() + suffix;
        return realName;
    }

    private static File writeFile(MultipartFile file, String fileName0) {
        File file2;
        try {
            file2 = new File(fileName0);
            FileUtils.copyInputStreamToFile(file.getInputStream(), file2);
            log.info("写入文件: " + file2.getAbsolutePath());
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException("file upload error.", e);
        }
        return file2;
    }

    /**
     * 对图片进行包装
     *
     * @param imgParamMap
     * @param file2
     */
    private static String wrapImage(Map<String, Object> imgParamMap, File file2) {
        if (null != imgParamMap) {
            String optType = (String) imgParamMap.get("optType");
            if (StringUtils.isNotEmptyString(optType)) {
                // 如果是缩放
                if (optType.contains("scale")) {
                    int width = (int) imgParamMap.get("width");
                    int height = (int) imgParamMap.get("height");
                    if (width > 0 && height > 0) {
                        String fileName = ImageUtil.scaleImage(file2, width, height);
                        return fileName;
                    }
                }
            }
        }
        return null;
    }


}
